package com.zyf.service;

import cn.hutool.core.io.FileUtil;
import com.zyf.service.audio.HandleAudioService;
import com.zyf.service.video.HandleVideoService;
import com.zyf.service.video.VedioUtils;
import com.zyf.tts.TTS;
import com.zyf.tts.TTSVoice;
import com.zyf.tts.bean.Voice;
import com.zyf.utils.*;
import it.sauronsoftware.jave.AudioAttributes;
import it.sauronsoftware.jave.Encoder;
import it.sauronsoftware.jave.EncodingAttributes;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FrameRecorder;

import javax.imageio.ImageIO;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 短视频制作处理类
 */
public class HandleGSCVideoBP {

    private static final double RATE = 0.002;

    private static final String TTSURL = "http://192.168.1.2:9880";

    private static final String REFPATH = "./参考音频/[诗词]诗词.wav";

    private static final String REFTEXT = "明朝身不至,百忧非我所三乐事无事.";

    /**
     * 批量一键生成图签视频
     */
    public void batchMakeShortVideos(String folderPath) throws Exception {
        //先批量生成配音文件
        List<File> srcTxtFiles = FileUtil.loopFiles(folderPath, backfile -> backfile.isFile() && backfile.getName().endsWith(".txt"));
        List<File> txtFiles = new ArrayList<>();
        for (File file : srcTxtFiles) {
            List<File> mp4FinalList = FileUtil.loopFiles(file.getParent(), mp4file -> mp4file.isFile() && mp4file.getName().endsWith(".mp4") && mp4file.getName().contains("zimufinal"));
            if (!ListUtil.isEmpty(mp4FinalList)) {
                continue;
            }
            txtFiles.add(file);
        }
        List<List<File>> pageList = splitList(txtFiles, 30);//30个一批进行处理
        List<String> errorFile=new ArrayList<>();
        for (List<File> pages : pageList) {
            List<File> handDataList = new ArrayList<>();
            for (File file : pages) {
                try {
                    handleSingleTTS(TTSURL, REFPATH, REFTEXT, file.getAbsolutePath());
                    handDataList.add(file.getParentFile());
                } catch (Exception e) {
                    System.out.println(e.toString());
                    errorFile.add(e.toString());
                }
            }
            //遍历文件夹批量处理
            List<String> tips = new ArrayList<>();
            for (File file : handDataList) {
                try {
                    String fielfolderPath = file.getAbsolutePath();
                    List<File> backList = FileUtil.loopFiles(fielfolderPath, backfile -> backfile.isFile() && (backfile.getName().endsWith(".mp3") || backfile.getName().endsWith(".wav")) && backfile.getName().contains("back"));
                    List<File> srcList = FileUtil.loopFiles(fielfolderPath, srcfile -> srcfile.isFile() && (srcfile.getName().endsWith(".mp3") || srcfile.getName().endsWith(".wav")) && !srcfile.getName().contains("back"));
                    List<File> mp4BackList = FileUtil.loopFiles(fielfolderPath, mp4file -> mp4file.isFile() && (mp4file.getName().endsWith(".mp4")) && mp4file.getName().contains("back"));
                    List<File> srctxtList = FileUtil.loopFiles(fielfolderPath, txtfile -> txtfile.isFile() && txtfile.getName().endsWith(".txt"));
                    makeVideoByTag(srcList.get(0).getAbsolutePath(), backList.get(0).getAbsolutePath(), mp4BackList.get(0).getAbsolutePath(), srctxtList.get(0).getAbsolutePath());
                    //删除多余的文件
                    List<File> mp4FinalList = FileUtil.loopFiles(fielfolderPath, mp4file -> mp4file.isFile() && mp4file.getName().endsWith(".mp4") && !mp4file.getName().contains("zimufinal"));
                    List<File> wavFinalList = FileUtil.loopFiles(fielfolderPath, wavfile -> wavfile.isFile() && wavfile.getName().endsWith(".wav") && (wavfile.getName().contains("hebing") || wavfile.getName().contains("back") || wavfile.getName().contains("merge")));
                    if (!ListUtil.isEmpty(mp4FinalList)) {
                        for (File mp4File : mp4FinalList) {
                            mp4File.delete();
                        }
                    }
                    if (!ListUtil.isEmpty(wavFinalList)) {
                        for (File wavFile : wavFinalList) {
                            wavFile.delete();
                        }
                    }
                } catch (Exception e) {
                    tips.add(e.toString());
                }
            }
        }
        System.out.println(errorFile.toString());
    }

    /**
     * 分割集合
     *
     * @param list
     * @param pageSize
     * @param <T>
     * @return
     */
    private <T> List<List<T>> splitList(List<T> list, int pageSize) {
        List<List<T>> pages = new ArrayList<>();
        int size = list.size();
        int pageCount = (size + pageSize - 1) / pageSize;
        for (int i = 0; i < pageCount; i++) {
            int fromIndex = i * pageSize;
            int toIndex = Math.min((i + 1) * pageSize, size);
            List<T> page = list.subList(fromIndex, toIndex);
            pages.add(page);
        }
        return pages;
    }

    /**
     * 调用GSV接口 9880
     *
     * @param txtFile
     * @return
     * @throws IOException
     */
    public void handleSingleTTS(String url, String refPath, String refText, String txtFile) throws Exception {
        File file = new File(txtFile);
        //读取源文件
        String srcContent = getSrcTxtByLine(txtFile);
        //设置请求参数
        StringBuffer param = new StringBuffer();
        param.append("text=" + URLEncoder.encode(srcContent, "utf-8"));
        param.append("&text_lang=zh&");
        param.append("ref_audio_path=" + URLEncoder.encode(refPath, "utf-8"));
        param.append("&prompt_lang=zh&");
        param.append("prompt_text=" + URLEncoder.encode(refText, "utf-8"));
        param.append("&text_split_method=cut5&batch_size=20&media_type=wav&speed_factor=1.0");

        HttpClientUtils.doGet(url, param.toString());
        //新文件夹路径
        String wavPath = "F:\\project\\GPT_SOVTTS\\GPT-SoVITS-v2\\音频输出\\audio.wav";
        String srtPath = "F:\\project\\GPT_SOVTTS\\GPT-SoVITS-v2\\音频输出\\tts-out.srt";
        //复制文件
        copyFile(wavPath, file.getParent());
        copyFile(srtPath, file.getParent());
    }

    public String getSrcTxtByLine(String filepath) throws FileNotFoundException {
        String[] punctuation = {"。", "，", "、", "；", "：", "？", "！", "•", ".", "—"};
        List<String> punctuations = Arrays.asList(punctuation);
        StringBuffer buffer = new StringBuffer();
        InputStream inputstream = new FileInputStream(new File(filepath));
        BufferedReader reader = null;
        String temp = "";
        try {
            int index = 0;
            reader = new BufferedReader(new InputStreamReader(inputstream));
            while (!StringUtil.isBlank(temp = reader.readLine())) {
                if (index > 1) {
                    buffer.append(temp.trim());
                } else {
                    buffer.append(temp.trim() + "—");
                    buffer.append("\n");
                }
                index++;
            }
        } catch (IOException e) {

        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return buffer.toString();
    }

    /**
     * 一键合成文字书签视频
     *
     * @return
     * @throws Exception
     */
    public boolean makeVideoByTag(String audiopath, String backpath, String mp4Path, String srctxtPath) throws Exception {
        try {
            //合成音频
            Map<String, String> resMap = mergeAudioAndBackBySrtAndTag(audiopath, backpath);
            //合成视频字幕
            String message = makeSingleVideo(mp4Path, resMap.get("audio"), resMap.get("srt"), srctxtPath);//合成视频
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
        return true;
    }


    /**
     * 制作单个的长视频
     */
    public String makeSingleVideo(String backMp4Path, String finalAudio, String finalSrt, String txtPath) throws Exception {
        //生成封面图片
        String coverimg = mergeSingleText2Image(txtPath);
        //抓取内容视频的宽高
        FFmpegFrameGrabber grabberVideo = null;
        FFmpegFrameGrabber grabberAudio = null;
        int width = 1300;
        int height = 1800;
        long durationAudio = 0;
        double frameRate = 0;
        int coverWidth = 0;
        int coverHeitht = 0;
        try {
            //抓取视频帧
            grabberVideo = new FFmpegFrameGrabber(backMp4Path);
            grabberAudio = new FFmpegFrameGrabber(finalAudio);
            grabberVideo.start();
            grabberAudio.start();
            //获取时长,以短的文件为主进行截取
            long durationVideo = grabberVideo.getFormatContext().duration() / 1000000;
            durationAudio = grabberAudio.getFormatContext().duration() / 1000000;
            frameRate = grabberVideo.getFrameRate();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (grabberVideo != null) {
                grabberVideo.stop();
                grabberVideo.release();
            }
            if (grabberAudio != null) {
                grabberAudio.stop();
                grabberAudio.release();
            }
        }
        //将语音文件和背景音乐合成
        System.out.println("-----开始提取视频");
        String backsingleVideo = new VedioUtils().splitSingleVideo(backMp4Path);
        System.out.println("-----提取视频结束");
        String backFilal = "";
        //调整背景视频的分辨率
        System.out.println("-----开始调整背景视频分辨率");
        backFilal = new HandleVideoService().updateVideoRate(backsingleVideo, width, height);
        System.out.println("-----调整背景视频分辨率结束");
        coverWidth = width;
        coverHeitht = height;
        //1.生成封面视频
        String firstMp4path = new File(backMp4Path).getParent() + File.separator + "first.mp4";
        createMp4ByFFmpegAndFrameRate(firstMp4path, coverimg, coverWidth, coverHeitht, frameRate, 2);//默认2秒
        //2.嵌入视频
        List<String> files = new ArrayList<>();
        files.add(firstMp4path);
        //延长背景视频
        String finalMp4 = extendVideo(backFilal, (durationAudio - 2) + "");
        //合成两个视频  String recursionVideos(List<String> fileList)
        files.add(finalMp4);
        String finalMa4Path = new VedioUtils().recursionVideos(files);
        //合成音频
        System.out.println("开始合成视频和音频-----");
        String mp4path = mergeVediosAndAudio(finalMa4Path, finalAudio);
        System.out.println("-----合成视频和音频结束");
        //合并视频和字幕
        new HandleVideoService().mergeVediosAndSrtByDoubleFile(mp4path, finalSrt);

        return "操作成功";
    }

    /**
     * 将单个文本合并到图片中
     */
    public String mergeSingleText2Image(String txtPath) throws Exception {
        //读取源文件
        String outpath = "";
        List<String> txtlist = getSrcTxt(txtPath);
        int srctotaline = txtlist.size();
        List<String> srclist = new ArrayList<>();
        if (srctotaline > 30) {//行数大于30,则进行单行4列组合
            StringBuffer buffer = new StringBuffer();
            for (int i = 0; i < srctotaline; i++) {
                String line = txtlist.get(i);
                if (i == 0 || i == 1) {
                    srclist.add(line);
                    continue;
                }
                if (i % 2 == 0) {
                    if (buffer.length() > 0) {
                        srclist.add(buffer.toString());
                        buffer.delete(0, buffer.length());
                    }
                    buffer.append(line);
                } else {
                    buffer.append(line);
                }
            }
        } else {
            srclist = txtlist;
        }
        InputStream inputstream = null;
        int imgHerght = 0;
        int imgWidth = 0;
        BufferedImage bimage = null;
        try {
            //图片加载到缓冲区
            inputstream = this.getClass().getClassLoader().getResourceAsStream("tag.jpg");
            bimage = ImageIO.read(inputstream);
            //图片的高
            imgHerght = bimage.getHeight();
            //图片的宽
            imgWidth = bimage.getWidth();
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            inputstream.close();
        }
        //计算字体大小
        int totaline = srclist.size();
        String fontsizeStr = imgHerght / (totaline * 2) + "";//减去间隔10*totalline-1,同时减去上下一个字的空隙
        int fontsize;
        if (fontsizeStr.contains(".")) {
            fontsize = Integer.valueOf(fontsizeStr.substring(0, fontsizeStr.indexOf(".")));
        } else {
            fontsize = Integer.valueOf(fontsizeStr);
        }
        //确定具体的字体大小
        if (fontsize >= 75) {
            fontsize = 75;
        } else if (fontsize >= 70) {
            fontsize = 70;
        } else if (fontsize >= 65) {
            fontsize = 65;
        } else if (fontsize >= 60) {
            fontsize = 60;
        } else if (fontsize >= 55) {
            fontsize = 55;
        } else if (fontsize >= 50) {
            fontsize = 50;
        } else if (fontsize >= 45) {
            fontsize = 45;
        } else if (fontsize >= 40) {
            fontsize = 40;
        } else if (fontsize >= 35) {
            fontsize = 35;
        } else if (fontsize >= 30) {
            fontsize = 30;
        } else if (fontsize >= 25) {
            fontsize = 25;
        } else if (fontsize >= 20) {
            fontsize = 20;
        } else if (fontsize >= 10) {
            fontsize = 13;
        }
        String intervalStr = fontsize * 0.8 + "";
        int interval;
        if (intervalStr.contains(".")) {
            interval = Integer.valueOf(intervalStr.substring(0, intervalStr.indexOf(".")));
        } else {
            interval = Integer.valueOf(intervalStr);
        }
        System.out.println("开始添加文字----");
        try {
            outpath = txtPath.replace(".txt", ".png");
            File file = new File(outpath);
            if (!file.exists()) {
                file.createNewFile();
            }
            for (String temp : srclist) {
                int maxtxtWidth = (temp.length() + 2) * fontsize;//留出两个字的边缘位置
                if (maxtxtWidth >= imgWidth) {
                    fontsize = imgWidth / (temp.length() + 2);
                    break;
                }
            }
            //确定文字的起始位置
            int initTxtY = (imgHerght - totaline * fontsize - (totaline - 1) * interval) / 2;
            Font font = new Font("宋体", Font.BOLD, fontsize);   //定义字体  楷体
            Color color = new Color(6, 3, 3, 241);
            for (String temp : srclist) {
                int res = ImageUtils.drawTextToImgByDefault(bimage, temp.trim(), outpath, font, initTxtY, color, imgWidth, fontsize);
                initTxtY += fontsize + interval;//10个的间隔
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        System.out.println("------添加文字结束");
        return outpath;
    }

    /**
     * 读取源文件
     */
    private List<String> getSrcTxt(String filepath) throws FileNotFoundException {
        List<String> srcTxtlist = new ArrayList<>();
        InputStream inputstream = new FileInputStream(new File(filepath));
        BufferedReader reader = null;
        String temp = "";
        try {
            reader = new BufferedReader(new InputStreamReader(inputstream));
            while ((temp = reader.readLine()) != null) {
                if (temp.length() > 0) {
                    srcTxtlist.add(temp);
                }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return srcTxtlist;
    }

    /**
     * 合并视频和音频,以长度短的为基准
     * <p>
     * ffmpeg -i input_video.mp4 -i input_audio.mp3 -c:v copy -c:a aac -strict experimental -b:a 192k output_video.mp4
     *
     * @throws Exception
     */
    public String mergeVediosAndAudio(String videoPath, String audioPath) throws Exception {
        String videoFinalfile = videoPath.replace(".mp4", "_final.mp4");
        File file = new File(videoFinalfile);
        if (file.exists()) {
            file.delete();
        }
        FFmpegFrameGrabber grabberVideo = null;
        FFmpegFrameGrabber grabberAudio = null;
        try {
            //抓取视频帧
            grabberVideo = new FFmpegFrameGrabber(videoPath);
            //抓取音频帧
            grabberAudio = new FFmpegFrameGrabber(audioPath);
            grabberVideo.start();
            grabberAudio.start();
            //获取时长,以短的文件为主进行截取
            long durationVideo = grabberVideo.getFormatContext().duration() / 1000000;
            long durationAudio = grabberAudio.getFormatContext().duration() / 1000000;
            if (durationVideo != durationAudio) {
                if (durationVideo > durationAudio) {//音频短则以音频长度为主
                    //截取视频
                    videoPath = new VedioUtils().cutVideoByDurationAndStartZ(videoPath, durationAudio);
                } else {
                    //截取音频
                    audioPath = new HandleAudioService().cutAudioByStart(audioPath, durationVideo, "wav");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (grabberVideo != null) {
                grabberVideo.stop();
                grabberVideo.release();
            }
            if (grabberAudio != null) {
                grabberAudio.stop();
                grabberAudio.release();
            }
        }
        try {
            List<String> commands = new ArrayList<>();
            commands.add("ffmpeg");
            commands.add("-i");
            commands.add(videoPath);
            commands.add("-i");
            commands.add(audioPath);
            commands.add("-c:v");
            commands.add("copy");
            commands.add("-c:a");
            commands.add("aac");
            commands.add("-strict");
            commands.add("experimental");
            commands.add("-b:a");
            commands.add("192k");
            commands.add(videoFinalfile);

            String res = FFmpegUtils.execFFmpegCommand(commands);
            System.out.println(res);
        } catch (Exception e) {
            throw new RuntimeException("ffmpeg执行异常" + e.getMessage());
        }
        return videoFinalfile;
    }

    /**
     * 延长视频到指定长度
     *
     * @param videopath
     * @param duation
     */
    public String extendVideo(String videopath, String duation) throws Exception {
        //获取视频原始时长
        FFmpegFrameGrabber grabberVideo = null;
        int durationVideo = 0;
        int total = Integer.valueOf(duation);
        try {
            //抓取视频帧
            grabberVideo = new FFmpegFrameGrabber(videopath);
            grabberVideo.start();
            //获取时长,以短的文件为主进行截取
            String resdura = grabberVideo.getFormatContext().duration() / 1000000 + "";

            durationVideo = Integer.valueOf(resdura);

        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            grabberVideo.release();
            grabberVideo.stop();
        }
        int circle = total / durationVideo + 1;
        String finalMp4Path = videopath.replace(".mp4", "_final.mp4");

        List<String> commands = new ArrayList<>();
        commands.add("ffmpeg");
        commands.add("-stream_loop");
        commands.add(circle + "");
        commands.add("-i");
        commands.add(videopath);
        commands.add("-c");
        commands.add("copy");
        commands.add(finalMp4Path);

        String res = FFmpegUtils.execFFmpegCommand(commands);
        System.out.println(res);
        //视频生成完毕后进行截取
        //将5分钟转化为时分秒
        int hours = total / 3600;
        int minus = (total % 3600) / 60;
        int second = total - hours * 3600 - minus * 60;
        StringBuffer buffer = new StringBuffer();
        if (hours < 10) {
            buffer.append("0" + hours);
        } else {
            buffer.append("" + hours);
        }
        buffer.append(":");
        if (minus < 10) {
            buffer.append("0" + minus);
        } else {
            buffer.append("" + minus);
        }
        buffer.append(":");
        if (second < 10) {
            buffer.append("0" + second);
        } else {
            buffer.append("" + second);
        }

        String finalPath = new VedioUtils().cutVideoByFFmpeg(finalMp4Path, "00:00:00", buffer.toString());
        File oldFile = new File(finalMp4Path);
        if (oldFile.exists()) {
            oldFile.delete();
        }
        return finalPath;
    }

    /**
     * 创建mp4指定帧率
     *
     * @param mp4SavePath
     * @param width
     * @param height
     * @throws FrameRecorder.Exception
     */
    public static void createMp4ByFFmpegAndFrameRate(String mp4SavePath, String imgFile, int width, int height, double frameRate, int duration) throws Exception {
        File mp4File = new File(mp4SavePath);
        if (mp4File.exists()) {
            mp4File.delete();
        }

        List<String> commands = new ArrayList<>();
        commands.add("ffmpeg");
        commands.add("-loop");
        commands.add("1");
        commands.add("-framerate");
        commands.add(frameRate + "");
        commands.add("-i");
        commands.add(imgFile);
        commands.add("-t");
        commands.add(duration + "");
        commands.add("-c:v");
        commands.add("libx264");
        commands.add("-b:v");
        commands.add("2000k");
        commands.add("-crf");
        commands.add("18");
        commands.add("-pix_fmt");
        commands.add("yuv420p");
        commands.add("-s");
        commands.add(width + "X" + height);
        commands.add(mp4SavePath);

        String res = FFmpegUtils.execFFmpegCommand(commands);
        System.out.println(res);
    }

    /**
     * 音频添加背景乐并生成字幕文件(音量默认0.1)
     */
    public Map<String, String> mergeAudioAndBackBySrtAndTag(String srcaudiopath, String backpath) throws Exception {
        Map<String, String> resMap = new HashMap<>();
        File audioFile = new File(srcaudiopath);
        if (!audioFile.exists()) {
            throw new RuntimeException("源音频不存在");
        }
        File backFile = new File(backpath);
        if (!backFile.exists()) {
            throw new RuntimeException("背景音频不存在");
        }
        //统一转为wav无损模式
        if (audioFile.getName().endsWith(".mp3")) {
            srcaudiopath = converAudio(srcaudiopath);
        }
        try {
            //源音频生成字幕文件
            List<File> srtList = FileUtil.loopFiles(audioFile.getParent(), file -> file.isFile() && file.getName().endsWith(".srt"));
            String finalsrt = handleSrtByDuration(srtList.get(0).getAbsolutePath(), 2500);
            resMap.put("srt", finalsrt);
            if (srtList.get(0).exists()) {
                srtList.get(0).delete();
            }
            //添加前缀
            String prefixaudio = createPrefix2Audio(srcaudiopath);
            String togetherAudio = mergeAudioByFFmpeg(prefixaudio, srcaudiopath);
            //合成音频根据ffmpeg
            String finalaudio = mixSingleAudioByFFmpeg(togetherAudio, backpath);
            //调大音量5倍
            String finaleVolumeAudio = controAudioVolume(finalaudio, 6f);
            resMap.put("audio", finaleVolumeAudio);
            List<File> srctxtList = FileUtil.loopFiles(audioFile.getParent(), file -> file.isFile() && file.getName().endsWith(".txt"));
            if (srctxtList == null || srctxtList.size() <= 0) {
                throw new RuntimeException("字幕源文件不存在");
            }
            File prefixaudiofile = new File(prefixaudio);
            if (prefixaudiofile.exists()) {
                prefixaudiofile.delete();
            }
            File srcaudiopathfile = new File(srcaudiopath.replace(".wav", ".mp3"));
            if (srcaudiopathfile.exists()) {
                srcaudiopathfile.delete();
            }
            File finalaudiofile = new File(finalaudio);
            if (finalaudiofile.exists()) {
                finalaudiofile.delete();
            }
            File backpathfile = new File(backpath.replace(".wav", ".mp3"));
            if (backpathfile.exists()) {
                backpathfile.delete();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return resMap;
    }

    /**
     * 指定音频添加指定背景乐,统一用wav无损模式处理音频
     * ffmpeg -i input1.wav -i input2.wav -filter_complex "[0:a][1:a]concat=n=2:v=0:a=1[out]" -map "[out]" output.wav
     *
     * @throws IOException
     */
    public String mergeAudioByFFmpeg(String prefile, String srcaudio) throws Exception {
        File audioFile = new File(srcaudio);
        if (!audioFile.exists()) {
            throw new RuntimeException("主音频文件不存在");
        }
        File backFile = new File(prefile);
        if (!backFile.exists()) {
            throw new RuntimeException("前缀音频文件不存在");
        }
        //格式统一转换为wav
        if (audioFile.getName().endsWith(".mp3")) {
            srcaudio = converAudio(srcaudio);
        }
        //格式统一转换为wav
        if (backFile.getName().endsWith(".mp3")) {
            prefile = converAudio(prefile);
        }
        String outpath = srcaudio.replace(".", "_merge.");
        File outFile = new File(outpath);
        if (outFile.exists()) {
            outFile.delete();
        }

        //拼接音频
        List<String> commands = new ArrayList<>();
        commands.add("ffmpeg");
        commands.add("-i");
        commands.add(prefile);
        commands.add("-i");
        commands.add(srcaudio);
        commands.add("-filter_complex");
        commands.add("\"[0:a][1:a]concat=n=2:v=0:a=1[out]\"");
        commands.add("-map");
        commands.add("\"[out]\"");
        commands.add(outpath);

        String result = FFmpegUtils.execFFmpegCommand(commands);
        System.out.println(result);

        return outpath;
    }

    /**
     * 给音频添加空白前摇
     */
    public String createPrefix2Audio(String audiopath) throws Exception {
        File audioFile = new File(audiopath);
        //转换格式为wav
        if (audioFile.getName().endsWith(".mp3")) {
            audiopath = new HandleAudioService().converAudio(audioFile.getAbsolutePath());
        }
        File outputFile = new File(audiopath.replace(".wav", "_final.wav"));
        List<AudioInputStream> audioInputStreams = new ArrayList<>();
        AudioInputStream mergedAudioStream = null;
        InputStream inputstream = null;
        try {
            inputstream = this.getClass().getClassLoader().getResourceAsStream("prefix.wav");
            //系统支持的格式
            AudioFileFormat.Type[] types = AudioSystem.getAudioFileTypes();
            for (AudioFileFormat.Type type : types) {
                System.out.println(type.getExtension());
            }
            long totalLength = 0;
            AudioFormat audioFormat = null;
            AudioInputStream audioInputStream = null;
            // 读取前缀音乐
            audioInputStream = AudioSystem.getAudioInputStream(inputstream);
            totalLength += audioInputStream.getFrameLength();
            audioFormat = audioInputStream.getFormat();
            audioInputStreams.add(audioInputStream);
            // 创建新的音频格式和流
            boolean isSigned = audioFormat.getEncoding() == AudioFormat.Encoding.PCM_SIGNED;
            AudioFormat newAudioFormat = new AudioFormat(audioFormat.getSampleRate(),
                    audioFormat.getSampleSizeInBits(),
                    audioFormat.getChannels(),
                    isSigned,
                    audioFormat.isBigEndian());
            mergedAudioStream = new AudioInputStream(
                    new SequenceInputStream(Collections.enumeration(audioInputStreams)),
                    newAudioFormat,
                    totalLength
            );
            // 写入合并后的音频流到输出文件
            AudioSystem.write(mergedAudioStream, AudioFileFormat.Type.WAVE, outputFile);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            // 关闭所有音频流
            for (AudioInputStream ais : audioInputStreams) {
                ais.close();
            }
            mergedAudioStream.close();
            inputstream.close();

        }
        return outputFile.getAbsolutePath();
    }

    /**
     * 调整音量大小
     * ffmpeg -i input.mp3 -af "volume=0.1" output.mp3
     * <p>
     * ffmpeg -i input.mp3 -af "volume=10dB" output.mp3
     */
    public String controAudioVolume(String audiopath, float volume) throws Exception {
        File audioFile = new File(audiopath);
        String fileName = audioFile.getName();
        if (!audioFile.exists()) {
            throw new RuntimeException("文件不存在");
        }
        String outpath = audiopath.replace(".", "_final_hebing.");
        //生成str字幕文件
        List<String> commands = new ArrayList<>();
        commands.add("ffmpeg");
        commands.add("-i");
        commands.add(audiopath);
        commands.add("-af");
        commands.add("\"volume=" + volume + "\"");
        commands.add(outpath);

        String result = FFmpegUtils.execFFmpegCommand(commands);
        System.out.println(result);
        return outpath;
    }

    /**
     * 指定音频添加指定背景乐,统一用wav无损模式处理音频
     * ffmpeg -i main_audio.mp3 -stream_loop -1 -i background_music.mp3 -filter_complex "[0:a][1:a]amix=inputs=2:duration=first" -c:a libmp3lame -qscale:a 2 output.mp3
     * ffmpeg -i main_audio.mp3 -i background_music.mp3 -filter_complex "[1:a]volume=0.5[a];[0:a][a]amix=inputs=2:duration=first" -c:a libmp3lame -qscale:a 2 output.mp3
     *
     * @throws IOException
     */
    public String mixSingleAudioByFFmpeg(String srcpath, String backpath) throws Exception {
        File audioFile = new File(srcpath);
        if (!audioFile.exists()) {
            throw new RuntimeException("主音频文件不存在");
        }
        File backFile = new File(backpath);
        if (!backFile.exists()) {
            throw new RuntimeException("背景音频文件不存在");
        }
        //格式统一转换为wav
        if (audioFile.getName().endsWith(".mp3")) {
            srcpath = converAudio(srcpath);
        }
        //格式统一转换为wav
        if (backFile.getName().endsWith(".mp3")) {
            backpath = converAudio(backpath);
        }
        String outpath = srcpath.replace(".", "_merge.");
        File outFile = new File(outpath);
        if (outFile.exists()) {
            outFile.delete();
        }

        //合并音频
        List<String> commands = new ArrayList<>();
        commands.add("ffmpeg");
        commands.add("-i");
        commands.add(srcpath);
        commands.add("-stream_loop");
        commands.add("-1");
        commands.add("-i");
        commands.add(backpath);
        commands.add("-filter_complex");
        commands.add("\"[1:a]volume=0.25[a];[0:a][a]amix=inputs=2:duration=first\"");
        commands.add("-c:a");
//        commands.add("libmp3lame");
        commands.add("pcm_s16le");//wav格式
        commands.add("-qscale:a");
        commands.add("2");
        commands.add(outpath);

        String result = FFmpegUtils.execFFmpegCommand(commands);
        System.out.println(result);

        return outpath;
    }

    /**
     * 处理字幕文件时间推移同时添加间隔时间
     */
    public String handleSrtByDuration(String srtFilepath, int realDuration) throws Exception {
        String finalsrt = "";
        //读取字幕文件
        BufferedReader reader = null;
        String temp = "";
        StringBuffer buffer_final = new StringBuffer();
        try {
            reader = new BufferedReader(new InputStreamReader(new FileInputStream(srtFilepath)));
            int num = 0;
            while ((temp = reader.readLine()) != null) {
                if ("".equals(temp)) {
                    continue;
                }
                //判断第一个字是否是中文,如果是则判断长度
                if (!isChinese(temp.substring(0, 1)) && temp.length() > 5) {
                    String[] times = temp.split("-->");
                    int index = 0;
                    for (String str : times) {
                        String[] resTimes = str.trim().split(":");
                        int time2 = Integer.valueOf(resTimes[1]);
                        int time3 = Integer.valueOf(resTimes[2].replace(",", ""));
                        int time3AndDutation = time3 + realDuration;
                        if (time3AndDutation > 60000) {
                            time2++;
                            time3 = time3AndDutation - 60000;
                        } else {
                            time3 = time3AndDutation;
                        }
                        buffer_final.append(resTimes[0]);
                        buffer_final.append(":");
                        if (time2 < 10) {
                            buffer_final.append("0" + time2);
                        } else {
                            buffer_final.append(time2 + "");
                        }
                        buffer_final.append(":");
                        String time3Str = "" + time3;
                        if (time3 < 10000) {
                            buffer_final.append("0" + time3Str.substring(0, 1) + "," + time3Str.substring(1));
                        } else {
                            buffer_final.append(time3Str.substring(0, 2) + "," + time3Str.substring(2));
                        }
                        if (index == 0) {
                            buffer_final.append(" --> ");
                        }
                        index++;
                    }
                    buffer_final.append("\n");
                    num++;
                } else {
                    if (isChinese(temp.substring(0, 1))) {
                        buffer_final.append(temp);
                        buffer_final.append("\n");
                    } else {
                        if (temp.length() < 5) {
                            buffer_final.append("\n");
                        }
                        buffer_final.append(temp);
                        buffer_final.append("\n");
                    }
                }
            }
        } catch (IOException e) {
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        //写入文件
        FileWriter writer = null;
        try {
            finalsrt = srtFilepath.replace(".srt", "_final.srt");
            writer = new FileWriter(finalsrt, false);
            writer.write(buffer_final.toString());
            return finalsrt;
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (writer != null) {
                writer.flush();
                writer.close();
            }
        }
    }

    public boolean isChinese(String str) {
        boolean isChinese = true;
        for (char c : str.toCharArray()) {
            if (!Character.isIdeographic(c)) {
                isChinese = false;
                break;
            }
        }
        return isChinese;
    }

    /**
     * 音频转换
     */
    public String converAudio(String audioFilePath) {
        File inaudioFile = new File(audioFilePath);
        if (!inaudioFile.exists()) {
            throw new RuntimeException("音频文件不存在");
        }
        String filename = inaudioFile.getName();
        if (filename.contains("mp3")) {//默认转wav
            String outFilePath = audioFilePath.replace(".mp3", ".wav");
            File outFile = new File(outFilePath);
            try {
                AudioAttributes audioAttributes = new AudioAttributes();
                audioAttributes.setCodec("pcm_s16le");
                audioAttributes.setBitRate(new Integer(128000));
                audioAttributes.setChannels(new Integer(2));
                audioAttributes.setSamplingRate(new Integer(44100));

                EncodingAttributes encodingAttributes = new EncodingAttributes();
                encodingAttributes.setFormat("wav");
                encodingAttributes.setAudioAttributes(audioAttributes);

                Encoder encoder = new Encoder();
                encoder.encode(inaudioFile, outFile, encodingAttributes);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            return outFilePath;
        }
        if (filename.contains("wav")) {//默认转mp3
            String mp3FilePath = audioFilePath.replace(".wav", ".mp3");
            File outFile = new File(mp3FilePath);
            try {
                AudioAttributes audioAttributes = new AudioAttributes();
                audioAttributes.setCodec("libmp3lame");
                audioAttributes.setBitRate(new Integer(128080));
                audioAttributes.setChannels(new Integer(2));
                audioAttributes.setSamplingRate(new Integer(44100));

                EncodingAttributes encodingAttributes = new EncodingAttributes();
                encodingAttributes.setFormat("mp3");
                encodingAttributes.setAudioAttributes(audioAttributes);

                Encoder encoder = new Encoder();
                encoder.encode(inaudioFile, outFile, encodingAttributes);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            return mp3FilePath;
        }
        return "";
    }


    /**
     * 读取源文件
     */
    private List<String> checkSrcTxtByLine(String filepath) throws FileNotFoundException {
        List<String> messages = new ArrayList<>();
        InputStream inputstream = new FileInputStream(new File(filepath));
        BufferedReader reader = null;
        String temp = "";
        List<String> newSrtList = new ArrayList<>();
        try {
            reader = new BufferedReader(new InputStreamReader(inputstream));
            while ((temp = reader.readLine()) != null) {

            }
        } catch (IOException e) {
            if (reader != null)
                try {
                    reader.close();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return messages;
    }

    /**
     * 处理诗词文件,移动背景音乐,视频
     */
    public void handleTXT(String txtFile, String videoFolder) throws Exception {
        File back = new File(txtFile);
        List<File> sourceFile = FileUtil.loopFiles(back.getParent(), file -> file.isFile() && (file.getName().endsWith(".mp3") || file.getName().endsWith(".wav")));
        List<File> mp4list = FileUtil.loopFiles(videoFolder, MP4file -> MP4file.isFile() && (MP4file.getName().endsWith(".mp4")));
        if (sourceFile == null || sourceFile.size() <= 0) {
            throw new RuntimeException("背景音乐不存在");
        }
        //创建一级文件夹
        String firstLevelFolder = txtFile.substring(0, txtFile.indexOf("."));
        File firstLevelFolderFile = new File(firstLevelFolder);
        if (!firstLevelFolderFile.exists()) {
            firstLevelFolderFile.mkdir();
        }
        //读取文本文件
        List<String> txtList = new ArrayList<>();
        StringBuffer buffer = new StringBuffer();
        InputStream inputstream = new FileInputStream(new File(txtFile));
        BufferedReader reader = null;
        String temp = "";
        try {
            reader = new BufferedReader(new InputStreamReader(inputstream));
            while ((temp = reader.readLine()) != null) {
                if (!StringUtil.isBlank(temp.trim())) {
                    if (temp.trim().contains("*********")) {
                        txtList.add(buffer.toString());
                        buffer = new StringBuffer();
                    } else {
                        buffer.append(temp.trim());
                        buffer.append("\n");
                    }
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (inputstream != null) {
                try {
                    inputstream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        //对文件批量处理
        String[] punctuation = {"。", "、", "；", "：", "？", "！", "•", ".", "，", "\n"};
        List<String> punctuations = Arrays.asList(punctuation);
        for (String str : txtList) {
            String folderName = "";
            String filename = str.substring(str.length() - 10, str.length());
            for (char name : filename.toCharArray()) {
                String nameStr = name + "";
                if (!punctuations.contains(nameStr)) {
                    if (folderName.length() > 3) {
                        break;
                    }
                    folderName = folderName + name;
                }
            }
            File newFolder = new File(firstLevelFolder + File.separator + folderName);
            if (!newFolder.exists()) {
                newFolder.mkdir();
            }
            //复制背景音乐
            copyFile(sourceFile.get(0).getAbsolutePath(), newFolder.getAbsolutePath());
            int randomNumber = (int) (Math.random() * (mp4list.size()));
            //复制背景视频
            File videoFile = mp4list.get(randomNumber);
            copyFile(videoFile.getAbsolutePath(), newFolder.getAbsolutePath());
            //写入文件
            FileWriter writer = null;
            try {
                String finalpath = newFolder.getAbsolutePath() + File.separator + folderName + ".txt";
                writer = new FileWriter(finalpath, false);
                writer.write(str);
            } catch (IOException e) {
                throw new RuntimeException(e);
            } finally {
                if (writer != null) {
                    writer.flush();
                    writer.close();
                }
            }
        }
    }

    private void copyFile(String sourceFile, String desfolder) throws IOException {
        // 源文件路径
        Path source = Paths.get(sourceFile);
        // 目标文件夹路径
        Path destinationDir = Paths.get(desfolder);
        // 目标文件路径
        Path destination = destinationDir.resolve(source.getFileName());
        // 确保目标文件夹存在
        Files.createDirectories(destinationDir);
        // 使用Files.copy()方法复制文件到目标文件夹
        Files.copy(source, destination);
    }


}
